package ilabx

import (
    "bytes"
    "crypto/aes"
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/binary"
    "encoding/hex"
    "errors"
    "fmt"
    "math/rand"
    "strconv"
    "time"
)

/**
组成结构：[expiry:long][type:byte][issuer id:long]。注：其中中括号只是标记，header组合时不需添加中括号。

参数说明：

参数	说明
expiry	过期时间：UTC以毫秒为单位，二进制8byte，Big endian。
type	类别：值为二进制，必填。1 - JSON, 2 - SYS, 0 - 保留。
Issue id	编号：由“实验空间”分配给各实验平台的唯一编号，二进制8 byte，Big endian。
 */
func MakeHeader(issueId int64) []byte {
    var (
        expiry int64 = time.Now().Unix() * 1000
        type_ byte = 1
    )
    header := make([]byte, 0)
    buf := bytes.NewBuffer(header)
    _ = binary.Write(buf, binary.BigEndian, expiry)
    _ = binary.Write(buf, binary.BigEndian, type_)
    _ = binary.Write(buf, binary.BigEndian, issueId)
    return buf.Bytes()
}

/**
payload 是64 bytes的整数倍。

组成结构：aes256(random long + body + aes padding, aes key)。
注：
aes256是AES256加密算法；
random long是随机的8 byte数字；
aes padding是自定义的字符串，为补足64 bytes的整数倍；
aes key 由“实验空间”生成并分配给各实验教学项目；
body为UTF8编码的JSON格式字符串。
 */
func MakePayload(aesKey string, body string) ([]byte, error) {
    random := rand.Int63()
    payload := make([]byte, 0)
    buf := bytes.NewBuffer(payload)
    _ = binary.Write(buf, binary.BigEndian, random)
    _ = binary.Write(buf, binary.BigEndian, body)
    if paddingLen := buf.Len() % 64; paddingLen != 0 {
        _ = binary.Write(buf, binary.BigEndian, make([]byte, 64 - paddingLen))
    }
    aesKey_, err := base64.StdEncoding.DecodeString(aesKey)
    if err != nil {
        return nil, err
    }
    block, _ := aes.NewCipher(aesKey_)
    dst := make([]byte, buf.Len())
    block.Encrypt(dst, buf.Bytes())
    return dst, nil
}

/**
signature说明

组成结构：base64(HmacSHA256(based64(raw header) + '.' + base64(raw payload), secret key))。
注：
raw header是上述中生成的header；
raw payload是上述中生成的payload；
secret key是HmacSHA256的秘钥，由“实验空间”提供。
 */
func MakeSignature(header, payload []byte, secretKey string) []byte {
    raw := base64.RawStdEncoding.EncodeToString(header) + "." + base64.StdEncoding.EncodeToString(payload)
    return ComputeHmacSha256(raw, secretKey)
}

func ComputeHmacSha256(message string, secret string) []byte {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    //	fmt.Println(h.Sum(nil))
    sha := hex.EncodeToString(h.Sum(nil))
    //	fmt.Println(sha)

    //	hex.EncodeToString(h.Sum(nil))
    return []byte(sha)
}

func Encrypt(aesKey, issueId, secretKey, body string) (string, error) {
    issueId_, err := strconv.ParseInt(issueId, 10, 64)
    if err != nil {
        return "", errors.New(fmt.Sprintf("issueId %v 不合法", issueId))
    }
    header := MakeHeader(issueId_)
    payload, err := MakePayload(aesKey, body)
    if err != nil {
        return "", err
    }
    signature := MakeSignature(header, payload, secretKey)
    return fmt.Sprintf("%s.%s.%s",
        base64.StdEncoding.EncodeToString(header),
        base64.StdEncoding.EncodeToString(payload),
        base64.StdEncoding.EncodeToString(signature)), nil
}

func Decrypt() {

}